vulkan: Optionally share one JSON manifest per driver between architectures
authorSimon McVittie <smcv@debian.org>
Thu, 25 Sep 2025 13:01:25 +0000 (21:01 +0800)
committerTimo Aaltonen <tjaalton@debian.org>
Wed, 7 Jan 2026 12:26:39 +0000 (14:26 +0200)
If the library_path is just a basename like `libvulkan_lvp.so`, then we
can share the same JSON manifest like `lvp_icd.json` between all of the
architectures, like we already do for Vulkan layers. The library will
be looked up in the dynamic linker's default search path in this case,
and in practice will be found in `${libdir}`. This is how the Mesa's
EGL driver and Vulkan layers work, how Mesa is packaged in Debian 13,
and also how the Nvidia proprietary driver works; it makes installation
simpler for distros, especially on multiarch systems like Debian and
the freedesktop.org SDK.

However, if we want a separate manifest per architecture in order to
be able to write the full path into it, we still need per-architecture
filename disambiguation like `lvp_icd.x86_64.json`.

We presumably still want a separate per architecture on Windows, because
the concept of a single monolithic `${libdir}` is less common there, and
it can also be helpful during development when setting `$VK_DRIVER_FILES`
to force the use of a specific driver installed in a non-default location.

Use the following parameter to passed to vk_icd_gen:
'--icd-lib-path', vulkan_icd_lib_path,
'--icd-filename', icd_file_name,
output : 'virtio_icd.' + vulkan_manifest_suffix,

and the output is passed by '--out', '@OUTPUT@',
so we can detect vulkan_manifest_per_architecture from the --out parameter in script.

Closes: https://gitlab.freedesktop.org/mesa/mesa/-/issues/13745
Signed-off-by: Simon McVittie <smcv@collabora.com>
Co-authored-by: Yonggang Luo <luoyonggang@gmail.com>
Reviewed-by: Mel Henning <mhenning@darkrefraction.com>
Reviewed-by: Matt Turner <mattst88@gmail.com>
Reviewed-by: Eric Engestrom <eric@igalia.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/37314>
Applied-upstream: 26.0, commit:b860ae309a42dce317d275000016abc2b4ebe687

Gbp-Pq: Name vulkan-Optionally-share-one-JSON-manifest-per-driver-betw.patch

16 files changed:
meson.build
meson.options
src/amd/vulkan/meson.build
src/asahi/vulkan/meson.build
src/broadcom/vulkan/meson.build
src/freedreno/vulkan/meson.build
src/gallium/targets/lavapipe/meson.build
src/gfxstream/guest/vulkan/meson.build
src/imagination/vulkan/meson.build
src/intel/vulkan/meson.build
src/intel/vulkan_hasvk/meson.build
src/microsoft/vulkan/meson.build
src/nouveau/vulkan/meson.build
src/panfrost/vulkan/meson.build
src/virtio/vulkan/meson.build
src/vulkan/util/vk_icd_gen.py

index f85cd266e8c6bd2747113715cb80f863240bacbe..4bf16762a9b8b0707426dca83fe83bf36bff8446 100644 (file)
@@ -2280,6 +2280,13 @@ else
   vulkan_icd_lib_path = get_option('prefix') / get_option('libdir')
 endif
 
+vulkan_manifest_per_architecture = get_option('vulkan-manifest-per-architecture')
+
+if vulkan_manifest_per_architecture
+  vulkan_manifest_suffix = '@0@.json'.format(host_machine.cpu())
+else
+  vulkan_manifest_suffix = 'json'
+endif
 
 subdir('include')
 subdir('bin')
index b1f98d7452aa4782dea14ab9a90ccf8b538dbddb..43c58236fba0363e1b9b2615bc95136931f72777 100644 (file)
@@ -286,6 +286,19 @@ option(
                 'Default: $datadir/vulkan/icd.d'
 )
 
+option(
+  'vulkan-manifest-per-architecture',
+  type : 'boolean',
+  value : true,
+  description : 'If true, Vulkan ICDs have a separate JSON manifest per ' +
+                'architecture, for example lvp_icd.x86_64.json. ' +
+                '(Recommended for non-default ${prefix}.) ' +
+                'If false, all architectures share a single JSON manifest, ' +
+                'for example lvp_icd.json, referencing the library by its ' +
+                'basename. ' +
+                '(Recommended for Unix OS distros installing into /usr.)'
+)
+
 option(
   'moltenvk-dir',
   type : 'string',
index 78b19aaa7a34b79643612d15861a14bcfa3b92e4..d73e6d5256437339efafb73ab7df6cb64756782b 100644 (file)
@@ -289,7 +289,8 @@ icd_command = [
   prog_python, '@INPUT0@',
   '--api-version', '1.4', '--xml', '@INPUT1@',
   '--sizeof-pointer', sizeof_pointer,
-  '--lib-path', vulkan_icd_lib_path / icd_file_name,
+  '--icd-lib-path', vulkan_icd_lib_path,
+  '--icd-filename', icd_file_name,
   '--out', '@OUTPUT@',
 ]
 if with_platform_windows
@@ -299,7 +300,7 @@ endif
 radeon_icd = custom_target(
   'radeon_icd',
   input : [vk_icd_gen, vk_api_xml],
-  output : 'radeon_icd.@0@.json'.format(host_machine.cpu()),
+  output : 'radeon_icd.' + vulkan_manifest_suffix,
   command : icd_command,
   build_by_default : true,
   install_dir : with_vulkan_icd_dir,
@@ -316,7 +317,8 @@ _dev_icd = custom_target(
     prog_python, '@INPUT0@',
     '--api-version', '1.4', '--xml', '@INPUT1@',
     '--sizeof-pointer', sizeof_pointer,
-    '--lib-path', meson.current_build_dir() / icd_file_name,
+    '--icd-lib-path', meson.current_build_dir(),
+    '--icd-filename', icd_file_name,
     '--out', '@OUTPUT@',
   ],
   build_by_default : true,
index 820ee2dc2da00e06adb6e16efda2224283e28802..a5e483cbcba5c78ee546e242af0f938def3ac1ae 100644 (file)
@@ -106,12 +106,13 @@ icd_file_name = libname_prefix + 'vulkan_asahi.' + libname_suffix
 
 asahi_icd = custom_target(
   input : [vk_icd_gen, vk_api_xml],
-  output : 'asahi_icd.@0@.json'.format(host_machine.cpu()),
+  output : 'asahi_icd.' + vulkan_manifest_suffix,
   command : [
     prog_python, '@INPUT0@',
     '--api-version', '1.4', '--xml', '@INPUT1@',
     '--sizeof-pointer', sizeof_pointer,
-    '--lib-path', vulkan_icd_lib_path / icd_file_name,
+    '--icd-lib-path', vulkan_icd_lib_path,
+    '--icd-filename', icd_file_name,
     '--out', '@OUTPUT@',
   ],
   build_by_default : true,
@@ -128,7 +129,8 @@ custom_target(
     prog_python, '@INPUT0@',
     '--api-version', '1.4', '--xml', '@INPUT1@',
     '--sizeof-pointer', sizeof_pointer,
-    '--lib-path', meson.current_build_dir() / icd_file_name,
+    '--icd-lib-path', meson.current_build_dir(),
+    '--icd-filename', icd_file_name,
     '--out', '@OUTPUT@',
   ],
   build_by_default : true,
index 42c1e351ee311568408ab5fbffd04b0fe805c27c..d5cdbcd1ad5ec2dcec8a3d9ce4bfd5559a0c4534 100644 (file)
@@ -127,12 +127,13 @@ icd_file_name = libname_prefix + 'vulkan_broadcom.' + libname_suffix
 broadcom_icd = custom_target(
   'broadcom_icd',
   input : [vk_icd_gen, vk_api_xml],
-  output : 'broadcom_icd.@0@.json'.format(host_machine.cpu()),
+  output : 'broadcom_icd.' + vulkan_manifest_suffix,
   command : [
     prog_python, '@INPUT0@',
     '--api-version', '1.3', '--xml', '@INPUT1@',
     '--sizeof-pointer', sizeof_pointer,
-    '--lib-path', vulkan_icd_lib_path / icd_file_name,
+    '--icd-lib-path', vulkan_icd_lib_path,
+    '--icd-filename', icd_file_name,
     '--out', '@OUTPUT@',
   ],
   build_by_default : true,
@@ -150,7 +151,8 @@ _dev_icd = custom_target(
     prog_python, '@INPUT0@',
     '--api-version', '1.3', '--xml', '@INPUT1@',
     '--sizeof-pointer', sizeof_pointer,
-    '--lib-path', meson.current_build_dir() / icd_file_name,
+    '--icd-lib-path', meson.current_build_dir(),
+    '--icd-filename', icd_file_name,
     '--out', '@OUTPUT@',
   ],
   build_by_default : true,
index 18e6aba138702e3cebab22e1ab0480bd191b2851..c530d6ae835117530d5cc84ec5e0f874e971c02b 100644 (file)
@@ -202,12 +202,13 @@ icd_file_name = libname_prefix + 'vulkan_freedreno.' + libname_suffix
 freedreno_icd = custom_target(
   'freedreno_icd',
   input : [vk_icd_gen, vk_api_xml],
-  output : 'freedreno_icd.@0@.json'.format(host_machine.cpu()),
+  output : 'freedreno_icd.' + vulkan_manifest_suffix,
   command : [
     prog_python, '@INPUT0@',
     '--api-version', '1.4', '--xml', '@INPUT1@',
     '--sizeof-pointer', sizeof_pointer,
-    '--lib-path', vulkan_icd_lib_path / icd_file_name,
+    '--icd-lib-path', vulkan_icd_lib_path,
+    '--icd-filename', icd_file_name,
     '--out', '@OUTPUT@',
   ],
   build_by_default : true,
@@ -225,7 +226,8 @@ _dev_icd = custom_target(
     prog_python, '@INPUT0@',
     '--api-version', '1.4', '--xml', '@INPUT1@',
     '--sizeof-pointer', sizeof_pointer,
-    '--lib-path', meson.current_build_dir() / icd_file_name,
+    '--icd-lib-path', meson.current_build_dir(),
+    '--icd-filename', icd_file_name,
     '--out', '@OUTPUT@',
   ],
   build_by_default : true,
index b79e3a4ca25b8407b69985e3d403722c1c781f96..d1d4e5ba2b3ec501ca5ca445aea60ff4ed729f75 100644 (file)
@@ -24,7 +24,8 @@ icd_command = [
   prog_python, '@INPUT0@',
   '--api-version', '1.4', '--xml', '@INPUT1@',
   '--sizeof-pointer', sizeof_pointer,
-  '--lib-path', vulkan_icd_lib_path / icd_file_name,
+  '--icd-lib-path', vulkan_icd_lib_path,
+  '--icd-filename', icd_file_name,
   '--out', '@OUTPUT@',
 ]
 if host_machine.system() == 'windows'
@@ -34,7 +35,7 @@ endif
 lvp_icd = custom_target(
   'lvp_icd',
   input : [vk_icd_gen, vk_api_xml],
-  output : 'lvp_icd.@0@.json'.format(host_machine.cpu()),
+  output : 'lvp_icd.' + vulkan_manifest_suffix,
   command : icd_command,
   build_by_default : true,
   install_dir : with_vulkan_icd_dir,
@@ -51,7 +52,8 @@ _dev_icd = custom_target(
     prog_python, '@INPUT0@',
     '--api-version', '1.4', '--xml', '@INPUT1@',
     '--sizeof-pointer', sizeof_pointer,
-    '--lib-path', meson.current_build_dir() / icd_file_name,
+    '--icd-lib-path', meson.current_build_dir(),
+    '--icd-filename', icd_file_name,
     '--out', '@OUTPUT@',
   ],
   build_by_default : true,
index b00d5e39a1f52e8594c51a73ff40338d6327bb9c..004606f51b015852f09ab1b2ea4fd34eecc9aafe 100644 (file)
@@ -49,12 +49,13 @@ icd_file_name = libname_prefix + 'vulkan_gfxstream.' + libname_suffix
 gfxstream_icd = custom_target(
   'gfxstream_vk_icd',
   input : [vk_icd_gen, vk_api_xml],
-  output : 'gfxstream_vk_icd.@0@.json'.format(host_machine.cpu()),
+  output : 'gfxstream_vk_icd.' + vulkan_manifest_suffix,
   command : [
     prog_python, '@INPUT0@',
     '--api-version', '1.1', '--xml', '@INPUT1@',
     '--sizeof-pointer', sizeof_pointer,
-    '--lib-path', vulkan_icd_lib_path / icd_file_name,
+    '--icd-lib-path', vulkan_icd_lib_path,
+    '--icd-filename', icd_file_name,
     '--out', '@OUTPUT@',
   ],
   build_by_default : true,
@@ -71,7 +72,8 @@ _dev_icd = custom_target(
     prog_python, '@INPUT0@',
     '--api-version', '1.3', '--xml', '@INPUT1@',
     '--sizeof-pointer', sizeof_pointer,
-    '--lib-path', meson.current_build_dir() / icd_file_name,
+    '--icd-lib-path', meson.current_build_dir(),
+    '--icd-filename', icd_file_name,
     '--out', '@OUTPUT@',
   ],
   build_by_default : true,
index 245cd94f1a2e8dc4e9645598b7969a00651e946f..dfc3479d0009ba52ca853d116125d7a0e764d441 100644 (file)
@@ -141,12 +141,13 @@ icd_file_name = libname_prefix + 'vulkan_powervr_mesa.' + libname_suffix
 powervr_mesa_icd = custom_target(
   'powervr_mesa_icd',
   input : [vk_icd_gen, vk_api_xml],
-  output : 'powervr_mesa_icd.@0@.json'.format(host_machine.cpu()),
+  output : 'powervr_mesa_icd.' + vulkan_manifest_suffix,
   command : [
     prog_python, '@INPUT0@',
     '--api-version', '1.4', '--xml', '@INPUT1@',
     '--sizeof-pointer', sizeof_pointer,
-    '--lib-path', vulkan_icd_lib_path / icd_file_name,
+    '--icd-lib-path', vulkan_icd_lib_path,
+    '--icd-filename', icd_file_name,
     '--out', '@OUTPUT@',
   ],
   build_by_default : true,
@@ -163,7 +164,8 @@ _dev_icd = custom_target(
     prog_python, '@INPUT0@',
     '--api-version', '1.4', '--xml', '@INPUT1@',
     '--sizeof-pointer', sizeof_pointer,
-    '--lib-path', meson.current_build_dir() / icd_file_name,
+    '--icd-lib-path', meson.current_build_dir(),
+    '--icd-filename', icd_file_name,
     '--out', '@OUTPUT@',
   ],
   build_by_default : true,
index 4963298aed5a3d6d1cc5fa24d3411e646c39d98a..e8101300ddf7db8c2194433bb512050b91d9c3cb 100644 (file)
@@ -51,12 +51,13 @@ icd_file_name = libname_prefix + 'vulkan_intel.' + libname_suffix
 intel_icd = custom_target(
   'intel_icd',
   input : [vk_icd_gen, vk_api_xml],
-  output : 'intel_icd.@0@.json'.format(host_machine.cpu()),
+  output : 'intel_icd.' + vulkan_manifest_suffix,
   command : [
     prog_python, '@INPUT0@',
     '--api-version', '1.4', '--xml', '@INPUT1@',
     '--sizeof-pointer', sizeof_pointer,
-    '--lib-path', vulkan_icd_lib_path / icd_file_name,
+    '--icd-lib-path', vulkan_icd_lib_path,
+    '--icd-filename', icd_file_name,
     '--out', '@OUTPUT@',
   ],
   build_by_default : true,
@@ -74,7 +75,8 @@ _dev_icd = custom_target(
     prog_python, '@INPUT0@',
     '--api-version', '1.4', '--xml', '@INPUT1@',
     '--sizeof-pointer', sizeof_pointer,
-    '--lib-path', meson.current_build_dir() / icd_file_name,
+    '--icd-lib-path', meson.current_build_dir(),
+    '--icd-filename', icd_file_name,
     '--out', '@OUTPUT@',
   ],
   build_by_default : true,
index ed5ac7463558ff1e7e7c462951aa5b89ff585717..ea1763429cb9602731ad399e2e161210d7de1843 100644 (file)
@@ -21,12 +21,13 @@ icd_file_name = libname_prefix + 'vulkan_intel_hasvk.' + libname_suffix
 intel_hasvk_icd = custom_target(
   'intel_hasvk_icd',
   input : [vk_icd_gen, vk_api_xml],
-  output : 'intel_hasvk_icd.@0@.json'.format(host_machine.cpu()),
+  output : 'intel_hasvk_icd.' + vulkan_manifest_suffix,
   command : [
     prog_python, '@INPUT0@',
     '--api-version', '1.3', '--xml', '@INPUT1@',
     '--sizeof-pointer', sizeof_pointer,
-    '--lib-path', vulkan_icd_lib_path / icd_file_name,
+    '--icd-lib-path', vulkan_icd_lib_path,
+    '--icd-filename', icd_file_name,
     '--out', '@OUTPUT@',
   ],
   build_by_default : true,
@@ -44,7 +45,8 @@ _dev_icd = custom_target(
     prog_python, '@INPUT0@',
     '--api-version', '1.3', '--xml', '@INPUT1@',
     '--sizeof-pointer', sizeof_pointer,
-    '--lib-path', meson.current_build_dir() / icd_file_name,
+    '--icd-lib-path', meson.current_build_dir(),
+    '--icd-filename', icd_file_name,
     '--out', '@OUTPUT@',
   ],
   build_by_default : true,
index 0349d2ddc4ec041889a2e42ec39e885de36d7416..99239a3e95bef245700a79644e58f7e801123ee7 100644 (file)
@@ -80,7 +80,8 @@ icd_command = [
    prog_python, '@INPUT0@',
    '--api-version', '1.1', '--xml', '@INPUT1@',
    '--sizeof-pointer', sizeof_pointer,
-   '--lib-path', vulkan_icd_lib_path / icd_file_name,
+   '--icd-lib-path', vulkan_icd_lib_path,
+   '--icd-filename', icd_file_name,
    '--out', '@OUTPUT@',
 ]
 
@@ -88,7 +89,8 @@ icd_dev_command = [
    prog_python, '@INPUT0@',
    '--api-version', '1.1', '--xml', '@INPUT1@',
    '--sizeof-pointer', sizeof_pointer,
-   '--lib-path', join_paths(meson.current_build_dir(), icd_file_name),
+   '--icd-lib-path', meson.current_build_dir(),
+   '--icd-filename', icd_file_name,
    '--out', '@OUTPUT@',
 ]
 
@@ -100,7 +102,7 @@ endif
 dzn_icd = custom_target(
   'dzn_icd',
   input : [vk_icd_gen, vk_api_xml],
-  output : 'dzn_icd.@0@.json'.format(host_machine.cpu()),
+  output : 'dzn_icd.' + vulkan_manifest_suffix,
   command : icd_command,
   build_by_default : true,
   install_dir : with_vulkan_icd_dir,
index bf6e2f7f74e9af9a99ba448360dc0550fea13ae4..e5f951b84c7ecad805303fda8b7688fece150fd9 100644 (file)
@@ -166,12 +166,13 @@ icd_file_name = libname_prefix + 'vulkan_nouveau.' + libname_suffix
 nouveau_icd = custom_target(
   'nouveau_icd',
   input : [vk_icd_gen, vk_api_xml],
-  output : 'nouveau_icd.@0@.json'.format(host_machine.cpu()),
+  output : 'nouveau_icd.' + vulkan_manifest_suffix,
   command : [
     prog_python, '@INPUT0@',
     '--api-version', '1.4', '--xml', '@INPUT1@',
     '--sizeof-pointer', sizeof_pointer,
-    '--lib-path', vulkan_icd_lib_path / icd_file_name,
+    '--icd-lib-path', vulkan_icd_lib_path,
+    '--icd-filename', icd_file_name,
     '--out', '@OUTPUT@',
   ],
   build_by_default : true,
@@ -189,7 +190,8 @@ custom_target(
     prog_python, '@INPUT0@',
     '--api-version', '1.4', '--xml', '@INPUT1@',
     '--sizeof-pointer', sizeof_pointer,
-    '--lib-path', meson.current_build_dir() / icd_file_name,
+    '--icd-lib-path', meson.current_build_dir(),
+    '--icd-filename', icd_file_name,
     '--out', '@OUTPUT@',
   ],
   build_by_default : true,
index 0f224db2464367bf59a09ef2f5ff1e4a27fb9560..e8ca0510d47821ebe54a9df690331bdb04defc1e 100644 (file)
@@ -241,12 +241,13 @@ icd_file_name = libname_prefix + 'vulkan_panfrost.' + libname_suffix
 panfrost_icd = custom_target(
   'panfrost_icd',
   input : [vk_icd_gen, vk_api_xml],
-  output : 'panfrost_icd.@0@.json'.format(host_machine.cpu()),
+  output : 'panfrost_icd.' + vulkan_manifest_suffix,
   command : [
     prog_python, '@INPUT0@',
     '--api-version', '1.4', '--xml', '@INPUT1@',
     '--sizeof-pointer', sizeof_pointer,
-    '--lib-path', vulkan_icd_lib_path / icd_file_name,
+    '--icd-lib-path', vulkan_icd_lib_path,
+    '--icd-filename', icd_file_name,
     '--out', '@OUTPUT@',
   ],
   build_by_default : true,
@@ -264,7 +265,8 @@ _dev_icd = custom_target(
     prog_python, '@INPUT0@',
     '--api-version', '1.4', '--xml', '@INPUT1@',
     '--sizeof-pointer', sizeof_pointer,
-    '--lib-path', meson.current_build_dir() / icd_file_name,
+    '--icd-lib-path', meson.current_build_dir(),
+    '--icd-filename', icd_file_name,
     '--out', '@OUTPUT@',
   ],
   build_by_default : true,
index e41faf685f36ee03b5f7794c41fe53ab85d066fd..2ad2b6ff1057862dfe939d7c7f1ca876392f5108 100644 (file)
@@ -20,12 +20,13 @@ icd_file_name = libname_prefix + 'vulkan_virtio.' + libname_suffix
 virtio_icd = custom_target(
   'virtio_icd',
   input : [vk_icd_gen, vk_api_xml],
-  output : 'virtio_icd.@0@.json'.format(host_machine.cpu()),
+  output : 'virtio_icd.' + vulkan_manifest_suffix,
   command : [
     prog_python, '@INPUT0@',
     '--api-version', '1.4', '--xml', '@INPUT1@',
     '--sizeof-pointer', sizeof_pointer,
-    '--lib-path', vulkan_icd_lib_path / icd_file_name,
+    '--icd-lib-path', vulkan_icd_lib_path,
+    '--icd-filename', icd_file_name,
     '--out', '@OUTPUT@',
   ],
   build_by_default : true,
@@ -43,7 +44,8 @@ _dev_icd = custom_target(
     prog_python, '@INPUT0@',
     '--api-version', '1.4', '--xml', '@INPUT1@',
     '--sizeof-pointer', sizeof_pointer,
-    '--lib-path', meson.current_build_dir() / icd_file_name,
+    '--icd-lib-path', meson.current_build_dir(),
+    '--icd-filename', icd_file_name,
     '--out', '@OUTPUT@',
   ],
   build_by_default : true,
index 7760dd6b0475fedd9dec0d668d7ddb30fb5c8741..d5fb0f07dd5d9c64b432aa150899a1c00ddb06e1 100644 (file)
@@ -22,6 +22,7 @@
 
 import argparse
 import json
+import os
 import re
 import xml.etree.ElementTree as et
 
@@ -48,8 +49,10 @@ if __name__ == '__main__':
                         help='Vulkan registry XML for patch version')
     parser.add_argument('--sizeof-pointer', required=False, type=int,
                         help='sizeof(void*) on the host cpu')
-    parser.add_argument('--lib-path', required=True,
-                        help='Path to installed library')
+    parser.add_argument('--icd-lib-path', required=True,
+                        help='Folder of icd lib_path to installed library')
+    parser.add_argument('--icd-filename', required=True,
+                        help='Filename of icd lib_path to installed library')
     parser.add_argument('--out', required=False,
                         help='Output json file.')
     parser.add_argument('--use-backslash', action='store_true',
@@ -63,7 +66,12 @@ if __name__ == '__main__':
     else:
         re.match(r'\d+\.\d+\.\d+', version)
 
-    lib_path = args.lib_path
+    lib_path = args.icd_filename
+    if args.out and len(os.path.basename(args.out).split('.')) == 3:
+        # The output filename is the form of '${icd_id}.${host_machine.cpu()}.json',
+        # that means vulkan_manifest_per_architecture are true.
+        lib_path = args.icd_lib_path + '/' + args.icd_filename
+
     if args.use_backslash:
         lib_path = lib_path.replace('/', '\\')